<?php
/**
 * WeCenter Framework
 *
 * An open source application development framework for PHP 5.2.2 or newer
 *
 * @package		WeCenter Framework
 * @author		WeCenter Dev Team
 * @copyright	Copyright (c) 20011 - 2013, WeCenter, Inc.
 * @license		http://www.wecenter.com/license/
 * @link		http://www.wecenter.com/
 * @since		Version 1.0
 * @filesource
 */

/**
 * WeCenter 系统函数类
 *
 * @package		WeCenter
 * @subpackage	System
 * @category	Libraries
 * @author		WeCenter Dev Team
 */

/**
 * 根据特定规则对数组进行排序
 *
 * 提取多维数组的某个键名，以便把数组转换成一位数组进行排序（注意：不支持下标，否则排序会出错）
 * 
 * @param  array
 * @param  string
 * @param  string
 * @return array
 */
function aasort($source_array, $order_field, $sort_type = 'DESC')
{
	if (! is_array($source_array) or sizeof($source_array) == 0)
	{
		return false;
	}
	
	foreach ($source_array as $array_key => $array_row)
	{
		$sort_array[$array_key] = $array_row[$order_field];
	}
	
	$sort_func = ($sort_type == 'ASC' ? 'asort' : 'arsort');
	
	$sort_func($sort_array);
	
	// 重组数组
	foreach ($sort_array as $key => $val)
	{
		$sorted_array[$key] = $source_array[$key];
	}
	
	return $sorted_array;
}

/**
 * 获取用户 IP
 * 
 * @return string
 */
function fetch_ip()
{
	if ($_SERVER['HTTP_X_FORWARDED_FOR'] and valid_internal_ip($_SERVER['REMOTE_ADDR']))
	{
		$ip_address = $_SERVER['HTTP_X_FORWARDED_FOR'];
	}
	
	if ($ip_address)
	{
		if (strstr($ip_address, ','))
		{
			$x = explode(',', $ip_address);
			$ip_address = end($x);
		}
	}
	
	if (!valid_ip($ip_address) AND $_SERVER['REMOTE_ADDR'])
	{
		$ip_address = $_SERVER['REMOTE_ADDR'];
	}
	
	if (!valid_ip($ip_address))
	{
		$ip_address = '0.0.0.0';
	}
	
	return $ip_address;
}

/**
 * 验证 IP 地址是否为内网 IP
 * 
 * @param string
 * @return string
 */
function valid_internal_ip($ip)
{ 
	if (!valid_ip($ip))
	{
		return false;
	}
	
	$ip_address = explode('.', $ip);
	
	if ($ip_address[0] == 10)
	{
		return true;
	}
	
	if ($ip_address[0] == 172 and $ip_address[1] > 15 and $ip_address[1] < 32)
	{
		return true;
	}
	
	if ($ip_address[0] == 192 and $ip_address[1] == 168)
	{
		return true;
	} 
	
	return false;
}

/**
 * 校验 IP 有效性
 * 
 * @param  string
 * @return boolean
 */
function valid_ip($ip)
{
	return Zend_Validate::is($ip, 'Ip');
}

if (! function_exists('iconv'))
{
	/**
	 * 系统不开启 iconv 模块时, 自建 iconv(), 使用 MB String 库处理
	 * 
	 * @param  string
	 * @param  string
	 * @param  string
	 * @return string
	 */
	function iconv($from_encoding = 'GBK', $target_encoding = 'UTF-8', $string)
	{
		return convert_encoding($string, $from_encoding, $target_encoding);
	}
}

if (! function_exists('iconv_substr'))
{
	/**
	 * 系统不开启 iconv_substr 模块时, 自建 iconv_substr(), 使用 MB String 库处理
	 * 
	 * @param  string
	 * @param  string
	 * @param  int
	 * @param  string
	 * @return string
	 */
	function iconv_substr($string, $start, $length, $charset = 'UTF-8')
	{
		return mb_substr($string, $start, $length, $charset);
	}
}

if (! function_exists('iconv_strpos'))
{
	/**
	 * 系统不开启 iconv_substr 模块时, 自建 iconv_strpos(), 使用 MB String 库处理
	 * 
	 * @param  string
	 * @param  string
	 * @param  int
	 * @param  string
	 * @return string
	 */
	function iconv_strpos($haystack, $needle, $offset = 0, $charset = 'UTF-8')
	{
		return mb_strpos($haystack, $needle, $offset, $charset);
	}
}

/**
 * 兼容性转码
 * 
 * 系统转换编码调用此函数, 会自动根据当前环境采用 iconv 或 MB String 处理
 * 
 * @param  string
 * @param  string
 * @param  string 
 * @return string
 */
function convert_encoding($string, $from_encoding = 'GBK', $target_encoding = 'UTF-8')
{
	if (function_exists('mb_convert_encoding'))
	{
		return mb_convert_encoding($string, str_replace('//IGNORE', '', strtoupper($target_encoding)), $from_encoding);
	}
	else
	{
		if (strtoupper($from_encoding) == 'UTF-16')
		{
			$from_encoding = 'UTF-16BE';
		}
		
		if (strtoupper($target_encoding) == 'UTF-16')
		{
			$target_encoding = 'UTF-16BE';
		}
		
		if (strtoupper($target_encoding) == 'GB2312' or strtoupper($target_encoding) == 'GBK')
		{
			$target_encoding .= '//IGNORE';
		}
		
		return iconv($from_encoding, $target_encoding, $string);
	}
}

/**
 * 兼容性转码 (数组)
 * 
 * 系统转换编码调用此函数, 会自动根据当前环境采用 iconv 或 MB String 处理, 支持多维数组转码
 * 
 * @param  array
 * @param  string
 * @param  string 
 * @return array
 */
function convert_encoding_array($data, $from_encoding = 'GBK', $target_encoding = 'UTF-8')
{
	return eval('return ' . convert_encoding(var_export($data, true) . ';', $from_encoding, $target_encoding));    
}

/**
 * 双字节语言版 strpos
 * 
 * 使用方法同 strpos()
 * 
 * @param  string
 * @param  string
 * @param  int
 * @param  string
 * @return string
 */
function cjk_strpos($haystack, $needle, $offset = 0, $charset = 'UTF-8')
{
	if (function_exists('iconv_strpos'))
	{
		return iconv_strpos($haystack, $needle, $offset, $charset);
	}
	
	return mb_strpos($haystack, $needle, $offset, $charset);
}

/**
 * 双字节语言版 substr
 * 
 * 使用方法同 substr(), $dot 参数为截断后带上的字符串, 一般场景下使用省略号
 * 
 * @param  string
 * @param  int
 * @param  int
 * @param  string
 * @param  string
 * @return string
 */
function cjk_substr($string, $start, $length, $charset = 'UTF-8', $dot = '')
{
	if (cjk_strlen($string, $charset) <= $length)
	{
		return $string;
	}
	
	if (function_exists('mb_substr'))
	{
		return mb_substr($string, $start, $length, $charset) . $dot;
	}
	else
	{
		return iconv_substr($string, $start, $length, $charset) . $dot;
	}
}
/**
 * 字符串截取，支持中文和其他编码
 * @param  [string]  $str     [字符串]
 * @param  integer $start   [起始位置]
 * @param  integer $length  [截取长度]
 * @param  string  $charset [字符串编码]
 * @param  boolean $suffix  [是否有省略号]
 * @return [type]           [description]
 */
function msubstr($str, $start=0, $length=15, $charset="utf-8", $suffix=true) {
    if(function_exists("mb_substr")) {
        return mb_substr($str, $start, $length, $charset);
    } elseif(function_exists('iconv_substr')) {
        return iconv_substr($str,$start,$length,$charset);
    }
    $re['utf-8']   = "/[\x01-\x7f]|[\xc2-\xdf][\x80-\xbf]|[\xe0-\xef][\x80-\xbf]{2}|[\xf0-\xff][\x80-\xbf]{3}/";
    $re['gb2312'] = "/[\x01-\x7f]|[\xb0-\xf7][\xa0-\xfe]/";
    $re['gbk']    = "/[\x01-\x7f]|[\x81-\xfe][\x40-\xfe]/";
    $re['big5']   = "/[\x01-\x7f]|[\x81-\xfe]([\x40-\x7e]|\xa1-\xfe])/";
    preg_match_all($re[$charset], $str, $match);
    $slice = join("",array_slice($match[0], $start, $length));
    if($suffix) {
        return $slice."…";
    }
    return $slice;
}
/**
 * 双字节语言版 strlen
 * 
 * 使用方法同 strlen()
 * 
 * @param  string
 * @param  string
 * @return string
 */
function cjk_strlen($string, $charset = 'UTF-8')
{
	if (function_exists('mb_strlen'))
	{
		return mb_strlen($string, $charset);
	}
	else
	{
		return iconv_strlen($string, $charset);
	}
}

/**
 * 递归创建目录
 * 
 * 与 mkdir 不同之处在于支持一次性多级创建, 比如 /dir/sub/dir/
 * 
 * @param  string
 * @param  int
 * @return boolean
 */
function make_dir($dir, $permission = 0777)
{
	$dir = rtrim($dir, '/') . '/';
	
	if (is_dir($dir))
	{
		return TRUE;
	}
	
	if (! make_dir(dirname($dir), $permission))
	{
		return FALSE;
	}
	
	return @mkdir($dir, $permission);
}

/**
 * jQuery jsonp 调用函数
 * 
 * 用法同 json_encode
 * 
 * @param  array
 * @param  string
 * @return string
 */
function jsonp_encode($json = array(), $callback = 'jsoncallback')
{
	if ($_GET[$callback])
	{
		return $_GET[$callback] . '(' . json_encode($json) . ')';
	}
	
	return json_encode($json);
}

/**
 * 时间友好型提示风格化（即微博中的XXX小时前、昨天等等）
 * 
 * 即微博中的 XXX 小时前、昨天等等, 时间超过 $time_limit 后返回按 out_format 的设定风格化时间戳
 * 
 * @param  int
 * @param  int
 * @param  string
 * @param  array
 * @param  int
 * @return string
 */
function date_friendly($timestamp, $time_limit = 604800, $out_format = 'Y-m-d H:i', $formats = null, $time_now = null)
{
	if (get_setting('time_style') == 'N')
	{
		return date($out_format, $timestamp);
	}
	
	if ($formats == null)
	{
		$formats = array('YEAR' => '%s 年前', 'MONTH' => '%s 月前', 'DAY' => '%s 天前', 'HOUR' => '%s 小时前', 'MINUTE' => '%s 分钟前', 'SECOND' => '%s 秒前');
	}
	
	$time_now = $time_now == null ? time() : $time_now;
	$seconds = $time_now - $timestamp;
	
	if ($seconds == 0)
	{
		$seconds = 1;
	}
	
	if ($time_limit != null && $seconds > $time_limit)
	{
		return date($out_format, $timestamp);
	}
	
	$minutes = floor($seconds / 60);
	$hours = floor($minutes / 60);
	$days = floor($hours / 24);
	$months = floor($days / 30);
	$years = floor($months / 12);
	
	if ($years > 0)
	{
		$diffFormat = 'YEAR';
	}
	else
	{
		if ($months > 0)
		{
			$diffFormat = 'MONTH';
		}
		else
		{
			if ($days > 0)
			{
				$diffFormat = 'DAY';
			}
			else
			{
				if ($hours > 0)
				{
					$diffFormat = 'HOUR';
				}
				else
				{
					$diffFormat = ($minutes > 0) ? 'MINUTE' : 'SECOND';
				}
			}
		}
	}
	
	$dateDiff = null;
	
	switch ($diffFormat)
	{
		case 'YEAR' :
			$dateDiff = sprintf($formats[$diffFormat], $years);
			break;
		case 'MONTH' :
			$dateDiff = sprintf($formats[$diffFormat], $months);
			break;
		case 'DAY' :
			$dateDiff = sprintf($formats[$diffFormat], $days);
			break;
		case 'HOUR' :
			$dateDiff = sprintf($formats[$diffFormat], $hours);
			break;
		case 'MINUTE' :
			$dateDiff = sprintf($formats[$diffFormat], $minutes);
			break;
		case 'SECOND' :
			$dateDiff = sprintf($formats[$diffFormat], $seconds);
			break;
	}
	
	return $dateDiff;
}
/**
 * 获得几天前，几小时前，几月前
 * @param int $time 时间戳
 * @param array $unit 时间单位
 * @return bool|string
 */
function date_before($time, $unit = null) {
	$time = intval($time);
	$unit = is_null($unit) ? array("年", "月", "星期", "天", "小时", "分钟", "秒") : $unit;
	switch (true) {
		case $time < (NOW - 31536000) :
			return floor((NOW - $time) / 31536000) . $unit[0] . '前';
		case $time < (NOW - 2592000) :
			return floor((NOW - $time) / 2592000) . $unit[1] . '前';
		case $time < (NOW - 604800) :
			return floor((NOW - $time) / 604800) . $unit[2] . '前';
		case $time < (NOW - 86400) :
			return floor((NOW - $time) / 86400) . $unit[3] . '前';
		case $time < (NOW - 3600) :
			return floor((NOW - $time) / 3600) . $unit[4] . '前';
		case $time < (NOW - 60) :
			return floor((NOW - $time) / 60) . $unit[5] . '前';
		default :
			return floor(NOW - $time) . $unit[6] . '前';
	}
}
/**
 * 根据一个时间戳得到详细信息
 * @param  [type] $time [时间戳]
 * @return [type]      
 * @author [yangsheng@yahoo.com]
 */
function getDateInfo($time){
    $day_of_week_cn=array("日","一","二","三","四","五","六"); //中文星期
    $week_of_month_cn = array('','第1周','第2周','第3周','第4周','第5周','第6周');#本月第几周
    $tenDays= getTenDays(date('j',$time)); #获得旬
    $quarter = getQuarter(date('n',$time),date('Y',$time));# 获取季度
     
    $dimDate = array(
        'date_key' => strtotime(date('Y-m-d',$time)), #日期时间戳
        'date_day' => date('Y-m-d',$time), #日期YYYY-MM-DD
        'current_year' => date('Y',$time),#数字年
        'current_quarter' => $quarter['current_quarter'], #季度
        'quarter_cn' =>$quarter['quarter_cn'],
        'current_month' =>date('n',$time),#月
        'month_cn' =>date('Y-m',$time), #月份
        'tenday_of_month' =>$tenDays['tenday_of_month'],#数字旬
        'tenday_cn' =>$tenDays['tenday_cn'],#中文旬
        'week_of_month' =>ceil(date('j',$time)/7), #本月第几周
        'week_of_month_cn' =>$week_of_month_cn[ceil(date('j',$time)/7)],#中文当月第几周
        'day_of_year' =>date('z',$time)+1,  #年份中的第几天
        'day_of_month' =>date('j',$time),#得到几号
        'day_of_week' =>date('w',$time)>0 ? date('w',$time):7,#星期几
        'day_of_week_cn' =>'星期'.$day_of_week_cn[date('w',$time)],
     );
    return $dimDate;
}
/**
 * 获得日期是上中下旬
 * @param  [int] $j [几号]
 * @return [array]    [description]
 * @author [yangsheng@yahoo.com]
 */
function getTenDays($j)
{  
    $j = intval($j);
     if($j < 1 || $j > 31){
        return false;#不是日期
    }
   $tenDays = ceil($j/10);
    switch ($tenDays) {
        case 1:#上旬
            return array('tenday_of_month'=>1,'tenday_cn'=>'上旬',);
            break;
        case 2:#中旬
             return array('tenday_of_month'=>2,'tenday_cn'=>'中旬',);
            break;       
        default:#下旬
            return array('tenday_of_month'=>3,'tenday_cn'=>'下旬',);
            break;
    }
    return false;
}
/**
 * 根据月份获得当前第几季度
 * @param  [int] $n [月份]
 * @param  [int] $y [年]
 * @return [array]    [description]
 */
function getQuarter($n,$y=null){
     $n = intval($n);
    if($n < 1 || $n > 12){
        return false;   #不是月份
    }
    $quarter = ceil($n/3);
    switch ($quarter) {
        case 1: #第一季度
            return array('current_quarter' => 1, 'quarter_cn'=>$y?$y.'-Q1':'Q1');
            break;
        case 2: #第二季度
            return array('current_quarter' => 2, 'quarter_cn'=>$y?$y.'-Q2':'Q2');
            break;
         case 3: #第三季度
            return array('current_quarter' => 3, 'quarter_cn'=>$y?$y.'-Q3':'Q3');
            break;
         case 4: #第四季度
            return array('current_quarter' => 4, 'quarter_cn'=>$y?$y.'-Q4':'Q4');
            break;
    }
     return false;
}
/**
 * 载入类库, 并实例化、加入队列
 * 
 * 路径从 system 开始计算，并遵循 Zend Freamework 路径表示法，即下划线 _ 取代 / , 如 core_config 表示 system/core/config.php
 * 
 * @param  string
 * @return object
 */
function &load_class($class)
{
	static $_classes = array();
	
	// Does the class exist?  If so, we're done...
	if (isset($_classes[$class]))
	{
		return $_classes[$class];
	}
	
	if (class_exists($class) === FALSE)
	{
		$file = AWS_PATH . preg_replace('#_+#', '/', $class) . '.php';
		
		if (! file_exists($file))
		{
			throw new Zend_Exception('Unable to locate the specified class: ' . $class . ' ' . preg_replace('#_+#', '/', $class) . '.php');
		}
		
		require_once $file;
	}
	
	$_classes[$class] = new $class();
	
	return $_classes[$class];
}

function _show_error($exception_message)
{
	$name = strtoupper($_SERVER['HTTP_HOST']);
		
	if ($exception_message)
	{
		$exception_message = htmlspecialchars($exception_message);
		
		$errorBlock = "<div class='system-error'><textarea rows='15' cols='60' onfocus='this.select()'>{$exception_message}</textarea></div>";
	}
	
	if (defined('IN_AJAX'))
	{
		return $exception_message;
	}
	
	return <<<EOF
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd"><html xml:lang="en" lang="en" xmlns="http://www.w3.org/1999/xhtml"><head><meta http-equiv="content-type" content="text/html; charset=UTF-8" /><meta http-equiv="Pragma" content="no-cache" /><meta http-equiv="Cache-Control" content="no-cache" /><meta http-equiv="Expires" content="Fri, 01 January 1999 01:00:00 GMT" /><title>{$name} System Error</title><style type='text/css'>body,div,dl,dt,dd,ul,ol,li,h1,h2,h3,h4,h5,h6,pre,form,fieldset,input,textarea,p,blockquote,th,td{margin:0;padding:0;}table{border-collapse:collapse;border-spacing:0;}address,caption,cite,code,dfn,em,strong,th,var{font-style:normal;font-weight:400;}ol,ul{list-style:none;}caption,th{text-align:left;}h1,h2,h3,h4,h5,h6{font-size:100%;font-weight:400;}q:before,q:after{content:'';}hr{display:none;}address{display:inline;}body{font-family:"Lucida Grande", "Lucida Sans Unicode", Helvetica, Arial, Verdana, sans-serif;font-size:.8em;width:100%;}h1{font-family:"Lucida Grande", "Lucida Sans Unicode", Helvetica, Arial, Verdana, sans-serif;font-size:1.9em;color:#fff;}h2{font-size:1.6em;font-weight:400;clear:both;margin:0 0 8px;}a{color:#3e70a8;}a:hover{color:#3d8ce4;}#branding{background:#484848;padding:8px;}#content{clear:both;overflow:hidden;padding:20px 15px 0;}* #content{height:1%;}.message{background-color:#f5f5f5;clear:both;border-color:#d7d7d7;border-style:solid;border-width:1px;margin:0 0 10px;padding:7px 7px 7px 30px;border-radius:5px;}.message.error{background-color:#f3dddd;color:#281b1b;font-size:1.3em;font-weight:700;border-color:#deb7b7;}.message.unspecific{background-color:#f3f3f3;color:#515151;border-color:#d4d4d4;font-size:10px;}.system-error{margin:10px 0;padding:5px 10px;}textarea{width:95%;height:300px;font-size:11px;font-family:"Helvetica Neue Ultra Light", Monaco,Lucida Console,Consolas,Courier,Courier New;line-height:16px;color:#474747;border:1px #bbb solid;border-radius:3px;padding:5px;}fieldset,img,abbr,acronym{border:0;}</style></head><body><div id='header'><div id='branding'><h1>{$name} System Error</h1></div></div><div id='content'><div class='message error'>There appears to be an error:{$errorBlock}</div><p class='message unspecific'>If you are seeing this page, it means there was a problem communicating with our database.  Sometimes this error is temporary and will go away when you refresh the page.<br />Sometimes the error will need to be fixed by an administrator before the site will become accessible again.<br /><br />You can try to refresh the page by clicking <a href="#" onclick="window.location=window.location; return false;">here</a></p></div></body></html>
EOF;
}

function show_error($exception_message, $error_message = '')
{
	@ob_end_clean();
	
	if (get_setting('report_diagnostics') == 'Y' AND class_exists('AWS_APP', false))
	{
		AWS_APP::mail()->send('wecenter_report@outlook.com', '[' . G_VERSION . '][' . G_VERSION_BUILD . '][' . get_setting('base_url') . ']' . $error_message, nl2br($exception_message), get_setting('site_name'), 'WeCenter');
	}
	
	echo _show_error($exception_message);
	exit;
}





/**
 * 判断文件或目录是否可写
 * 
 * @param  string
 * @return boolean
 */
function is_really_writable($file)
{
	// If we're on a Unix server with safe_mode off we call is_writable
	if (DIRECTORY_SEPARATOR == '/' and @ini_get('safe_mode') == FALSE)
	{
		return is_writable($file);
	}
	
	// For windows servers and safe_mode "on" installations we'll actually
	// write a file then read it.  Bah...
	if (is_dir($file))
	{
		$file = rtrim($file, '/') . '/is_really_writable_' . md5(rand(1, 100));
		
		if (! @file_put_contents($file, 'is_really_writable() test file'))
		{
			return FALSE;
		}
		else
		{
			@unlink($file);
		}
		
		return TRUE;
	}
	else if (($fp = @fopen($file, FOPEN_WRITE_CREATE)) === FALSE)
	{
		return FALSE;
	}
	
	return TRUE;
}

/**
 * 生成密码种子
 * 
 * @param  integer
 * @return string
 */
function fetch_salt($length = 4)
{
	for ($i = 0; $i < $length; $i++)
	{
		$salt .= chr(rand(97, 122));
	}
	
	return $salt;
}

/**
 * 根据 salt 混淆密码
 *
 * @param  string
 * @param  string
 * @return string
 */
function compile_password($password, $salt)
{
	// md5 password...
	if (strlen($password) == 32)
	{
		return md5($password . $salt);
	}
	
	$password = md5(md5($password) . $salt);
	
	return $password;
}

/**
 * 伪静态地址转换器
 * 
 * @param  string
 * @return string
 */
function get_js_url($url)
{
	if (substr($url, 0, 1) == '/')
	{
		$url = substr($url, 1);
		
		if (get_setting('url_rewrite_enable') == 'Y' AND $request_routes = get_request_route())		
		{
			if (strstr($url, '?'))
			{
				$request_uri = explode('?', $url);
				
				$query_string = $request_uri[1];
				
				$url = $request_uri[0];
			}
			else
			{
				unset($query_string);
			}
			
			foreach ($request_routes as $key => $val)
			{				
				if (preg_match('/^' . $val[0] . '$/', $url))
				{
					$url = preg_replace('/^' . $val[0] . '$/', $val[1], $url);
										
					break;
				}
			}
			
			if ($query_string)
			{
				$url .= '?' . $query_string;
			}
		}
		
		$url = get_setting('base_url') . '/' . ((get_setting('url_rewrite_enable') != 'Y') ? G_INDEX_SCRIPT : '') . $url;
	}
	
	return $url;
}


/**
 * 构造或解析路由规则后得到的请求地址数组
 * 
 * 返回二维数组, 二位数组, 每个规则占据一条, 被处理的地址通过下标 0 返回, 处理后的地址通过下标 1 返回
 * 
 * @param  boolean
 * @return array
 */
function get_request_route($positive = true)
{
	if (!$route_data = get_setting('request_route_custom'))
	{
		return false;
	}
	
	if ($request_routes = explode("\n", $route_data))
	{
		$routes = array();
		
		$replace_array = array("(:any)" => "([^\"'&#\?\/]+[&#\?\/]*[^\"'&#\?\/]*)", "(:num)" => "([0-9]+)");
		
		foreach ($request_routes as $key => $val)
		{
			$val = trim($val);
			
			if (empty($val))
			{
				continue;
			}
			
			if ($positive)
			{
				list($pattern, $replace) = explode('===', $val);
			}
			else
			{
				list($replace, $pattern) = explode('===', $val);
			}
			
			if (substr($pattern, 0, 1) == '/' and $pattern != '/')
			{
				$pattern = substr($pattern, 1);
			}
			
			if (substr($replace, 0, 1) == '/' and $replace != '/')
			{
				$replace = substr($replace, 1);
			}
			
			$pattern = addcslashes($pattern, "/\.?");
			
			$pattern = str_replace(array_keys($replace_array), array_values($replace_array), $pattern);
			
			$replace = str_replace(array_keys($replace_array), "\$1", $replace);
			
			$routes[] = array($pattern, $replace);
		}
		
		return $routes;
	}
}

/**
 * 删除 UBB 标识码
 * 
 * @param  string
 * @return string
 */
function strip_ubb($str)
{
	$str = preg_replace('/\[attach\]([0-9]+)\[\/attach]/', '<i>** ' . AWS_APP::lang()->_t('插入的附件') . ' **</i>', $str);
	$str = preg_replace('/\[[^\]]+\](http[s]?:\/\/[^\[]*)\[\/[^\]]+\]/', "\$1 ", $str);
	
	return preg_replace('/\[[^\]]+\]([^\[]*)\[\/[^\]]+\]/', "\$1", $str);
}

/**
 * 获取数组中随机一条数据
 * 
 * @param  array
 * @return mixed
 */
function array_random($arr)
{
	shuffle($arr);
	
	return end($arr);
}

/**
 * 获得二维数据中第二维指定键对应的值，并组成新数组 (不支持二维数组)
 * 
 * @param  array
 * @param  string
 * @return array
 */
function fetch_array_value($array, $key)
{
	if (! is_array($array) || empty($array))
	{
		return array();
	}
	
	$data = array();
	
	foreach ($array as $_key => $val)
	{
		$data[] = $val[$key];
	}
	
	return $data;
}

/**
 * 强制转换字符串为整型, 对数字或数字字符串无效
 * 
 * @param  mixed
 */
function intval_string(&$value)
{
	if (! is_numeric($value))
	{
		$value = intval($value);
	}
}

/**
 * 获取时差
 * 
 * @return string
 */
function get_time_zone()
{
	$time_zone = 0 + (date('O') / 100);
	
	if ($time_zone == 0)
	{
		return '';
	}
	
	if ($time_zone > 0)
	{
		return '+' . $time_zone;
	}
	
	return $time_zone;
}



/**
 * 递归读取文件夹的文件列表
 * 
 * 读取的目录路径可以是相对路径, 也可以是绝对路径, $file_type 为指定读取的文件后缀, 不设置则读取文件夹内所有的文件
 * 
 * @param  string
 * @param  string
 * @return array
 */
function fetch_file_lists($dir, $file_type = null)
{
	if ($file_type)
	{
		if (substr($file_type, 0, 1) == '.')
		{
			$file_type = substr($file_type, 1);
		}
	}
	
	$base_dir = realpath($dir);
	$dir_handle = opendir($base_dir);
	
	$files_list = array();
	
	while (($file = readdir($dir_handle)) !== false)
	{		
		if (substr($file, 0, 1) != '.' AND !is_dir($base_dir . '/' . $file))
		{
			if (($file_type AND H::get_file_ext($file, false) == $file_type) OR !$file_type)
			{
				$files_list[] = $base_dir . '/' . $file;
			}
		}
		else if (substr($file, 0, 1) != '.' AND is_dir($base_dir . '/' . $file))
		{
			if ($sub_dir_lists = fetch_file_lists($base_dir . '/' . $file, $file_type))
			{
				$files_list = array_merge($files_list, $sub_dir_lists);
			}	
		} 
	}
	
	return $files_list;
}

/**
 * 判断是否是合格的手机客户端
 * 
 * @return boolean
 */
function is_mobile()
{
	$user_agent = strtolower($_SERVER['HTTP_USER_AGENT']);
	
	if (preg_match('/playstation/i', $user_agent) OR preg_match('/ipad/i', $user_agent) OR preg_match('/ucweb/i', $user_agent))
	{
		return false;
	}
	
	if (preg_match('/iemobile/i', $user_agent) OR preg_match('/mobile\ssafari/i', $user_agent) OR preg_match('/iphone\sos/i', $user_agent) OR preg_match('/android/i', $user_agent) OR preg_match('/symbian/i', $user_agent) OR preg_match('/series40/i', $user_agent))
	{
		return true;
	}
	
	return false;
}

/**
 * 判断是否处于微信内置浏览器中
 * 
 * @return boolean
 */
function in_weixin()
{
	$user_agent = strtolower($_SERVER['HTTP_USER_AGENT']);
	
	if (preg_match('/micromessenger/i', $user_agent))
	{
		return true;
	}
	
	return false;
}

/**
 * CURL 获取文件内容
 * 
 * 用法同 file_get_contents
 * 
 * @param string
 * @param integerr
 * @return string
 */
function curl_get_contents($url, $timeout = 10)
{
	if (!function_exists('curl_init'))
	{
		throw new Zend_Exception('CURL not support');
	}

	$curl = curl_init();
	
	curl_setopt($curl, CURLOPT_URL, $url);
	curl_setopt($curl, CURLOPT_TIMEOUT, $timeout);
	curl_setopt($curl, CURLOPT_RETURNTRANSFER, TRUE);

	if (substr($url, 0, 8) == 'https://')
	{
		curl_setopt($curl, CURLOPT_SSL_VERIFYPEER, FALSE);
		curl_setopt($curl, CURLOPT_SSL_VERIFYHOST, FALSE);
	}
	
	$result = curl_exec($curl);
	
	curl_close($curl);
	
	return $result;
}

/**
 * 删除网页上看不见的隐藏字符串, 如 Java\0script
 *
 * @param	string
 */
function remove_invisible_characters(&$str, $url_encoded = TRUE)
{
	$non_displayables = array();
	
	// every control character except newline (dec 10)
	// carriage return (dec 13), and horizontal tab (dec 09)
	
	if ($url_encoded)
	{
		$non_displayables[] = '/%0[0-8bcef]/';	// url encoded 00-08, 11, 12, 14, 15
		$non_displayables[] = '/%1[0-9a-f]/';	// url encoded 16-31
	}
	
	$non_displayables[] = '/[\x00-\x08\x0B\x0C\x0E-\x1F\x7F]+/S';	// 00-08, 11, 12, 14-31, 127

	do
	{
		$str = preg_replace($non_displayables, '', $str, -1, $count);
	}
	while ($count);
}
/**
 * 打印输出数据
 * @param void $var
 */
function show($var) {
	if (is_bool($var)) {
		var_dump($var);
	} else if (is_null($var)) {
		var_dump(NULL);
	} else {
		echo "<pre style='padding:10px;border-radius:5px;background:#F5F5F5;border:1px solid #aaa;font-size:14px;line-height:18px;'>" . print_r($var, true) . "</pre>";
	}
}
/**
 * 获得浏览器版本
 */
function browser_info() {
	$agent = strtolower($_SERVER["HTTP_USER_AGENT"]);
	$browser = null;
	if (strstr($agent, 'msie 9.0')) {
		$browser = 'msie9';
	} else if (strstr($agent, 'msie 8.0')) {
		$browser = 'msie8';
	} else if (strstr($agent, 'msie 7.0')) {
		$browser = 'msie7';
	} else if (strstr($agent, 'msie 6.0')) {
		$browser = 'msie6';
	} else if (strstr($agent, 'firefox')) {
		$browser = 'firefox';
	} else if (strstr($agent, 'chrome')) {
		$browser = 'chrome';
	} else if (strstr($agent, 'safari')) {
		$browser = 'safari';
	} else if (strstr($agent, 'opera')) {
		$browser = 'opera';
	}
	return $browser;
}

/**
 * 跳转网址
 * @param string $url 跳转urlg
 * @param int $time 跳转时间
 * @param string $msg
 */
function go($url, $time = 0, $msg = '') {
	$url = U($url);
	if (!headers_sent()) {
		$time == 0 ? header("Location:" . $url) : header("refresh:{$time};url={$url}");
		exit($msg);
	} else {
		echo "<meta http-equiv='Refresh' content='{$time};URL={$url}'>";
		if ($time)
			exit($msg);
	}
}
/**
 * 是否为AJAX提交
 * @return boolean
 */
function ajax_request() {
	if (isset($_SERVER['HTTP_X_REQUESTED_WITH']) && strtolower($_SERVER['HTTP_X_REQUESTED_WITH']) == 'xmlhttprequest')
		return true;
	return false;
}
/**
 * 对数组或字符串进行转义处理，数据可以是字符串或数组及对象
 * @param void $data
 * @return type
 */
function addslashes_d($data) {
	if (is_string($data)) {
		return addslashes($data);
	}
	if (is_numeric($data)) {
		return $data;
	}
	if (is_array($data)) {
		$var = array();
		foreach ($data as $k => $v) {
			if (is_array($v)) {
				$var[$k] = addslashes_d($v);
				continue;
			} else {
				$var[$k] = addslashes($v);
			}
		}
		return $var;
	}
}

/**
 * 去除转义
 * @param type $data
 * @return type
 */
function stripslashes_d($data) {
	if (empty($data)) {
		return $data;
	} elseif (is_string($data)) {
		return stripslashes($data);
	} elseif (is_array($data)) {
		$var = array();
		foreach ($data as $k => $v) {
			if (is_array($v)) {
				$var[$k] = stripslashes_d($v);
				continue;
			} else {
				$var[$k] = stripslashes($v);
			}
		}
		return $var;
	}
}


/**
 * 将数组转为字符串表示形式
 * @param array $array 数组
 * @param int $level 等级不要传参数
 * @return string
 */
function array_to_String($array, $level = 0) {
	if (!is_array($array)) {
		return "'" . $array . "'";
	}
	$space = '';
	//空白
	for ($i = 0; $i <= $level; $i++) {
		$space .= "\t";
	}
	$arr = "Array\n$space(\n";
	$c = $space;
	foreach ($array as $k => $v) {
		$k = is_string($k) ? '\'' . addcslashes($k, '\'\\') . '\'' : $k;
		$v = !is_array($v) && (!preg_match("/^\-?[1-9]\d*$/", $v) || strlen($v) > 12) ? '\'' . addcslashes($v, '\'\\') . '\'' : $v;
		if (is_array($v)) {
			$arr .= "$c$k=>" . array_to_String($v, $level + 1);
		} else {
			$arr .= "$c$k=>$v";
		}
		$c = ",\n$space";
	}
	$arr .= "\n$space)";
	return $arr;
}

/**
 * 获得随机字符串
 * @param int $len 长度
 * @return string
 */
function rand_str($len = 6) {
	$data = 'abcdefghijklmnopqrstuvwxyz0123456789';
	$str = '';
	while (strlen($str) < $len)
		$str .= substr($data, mt_rand(0, strlen($data) - 1), 1);
	return $str;
}
/**
 * 用户定义常量
 * @param bool $view 是否显示
 * @param bool $tplConst 是否只获取__WEB__这样的常量
 * @return array
 */
function print_const($view = true, $tplConst = false) {
	$define = get_defined_constants(true);
	$const = $define['user'];
	if ($tplConst) {
		$const = array();
		foreach ($define['user'] as $k => $d) {
			if (preg_match('/^__/', $k)) {
				$const[$k] = $d;
			}
		}
	}
	if ($view) {
		p($const);
	} else {
		return $const;
	}
}
/**
 * 获取url
 * @return [type] [description]
 */
function getUrl(){
  $pageURL = 'http';
  if (isset($_SERVER["HTTPS"]) && $_SERVER["HTTPS"] == "on") {
    $pageURL .= "s";
  }
  $pageURL .= "://";
  if ($_SERVER["SERVER_PORT"] != "80") {
    $pageURL .= $_SERVER["HTTP_HOST"] . ":" . $_SERVER["SERVER_PORT"] . $_SERVER["REQUEST_URI"];
  } else {
    $pageURL .= $_SERVER["HTTP_HOST"] . $_SERVER["REQUEST_URI"];
  }
  return $pageURL;
}
/**
 * 获取当前站点的访问路径根目录
 * @return [type] [description]
 */
function getSiteUrl() {
    $uri = $_SERVER['REQUEST_URI']?$_SERVER['REQUEST_URI']:($_SERVER['PHP_SELF']?$_SERVER['PHP_SELF']:$_SERVER['SCRIPT_NAME']);
    return 'http://'.$_SERVER['HTTP_HOST'].substr($uri, 0, strrpos($uri, '/')+1);
}

/**
 * 下载
 * @param  [type] $filename [description]
 * @param  string $dir      [description]
 * @return [type]           [description]
 */
function downloads($filename,$dir='./'){
    $filepath = $dir.$filename;
    if (!file_exists($filepath)){
        header("Content-type: text/html; charset=utf-8");
        echo "File not found!";
        exit;
    } else {
        $file = fopen($filepath,"r");
        Header("Content-type: application/octet-stream");
        Header("Accept-Ranges: bytes");
        Header("Accept-Length: ".filesize($filepath));
        Header("Content-Disposition: attachment; filename=".$filename);
        echo fread($file, filesize($filepath));
        fclose($file);
    }
}
/**
 * 创建一个目录树
 * @param  [type]  $dir  [description]
 * @param  integer $mode [description]
 * @return [type]        [description]
 */
function mkdirs($dir, $mode = 0777) {
    if (!is_dir($dir)) {
        mkdirs(dirname($dir), $mode);
        return mkdir($dir, $mode);
    }
    return true;
}

    /*********************************************************************
    $id = "http://www.xiaoshuoshu.org/files/article/html/0/160/index.html";
     
    $token = encrypt($id, 'E', 'qingdou');
     
    echo '加密:'.encrypt($id, 'E', 'qingdou');
    echo '<br />';
     
    echo '解密：'.encrypt($token, 'D', 'qingdou');
     
    函数名称:encrypt
    函数作用:加密解密字符串
    使用方法:
    加密     :encrypt('str','E','qingdou');
    解密     :encrypt('被加密过的字符串','D','qingdou');
    参数说明:
    $string   :需要加密解密的字符串
    $operation:判断是加密还是解密:E:加密   D:解密
    $key      :加密的钥匙(密匙);
    *********************************************************************/
    function encrypt($string,$operation,$key='')
    {
        $src  = array("/","+","=");
        $dist = array("_a","_b","_c");
        if($operation=='D'){$string  = str_replace($dist,$src,$string);}
        $key=md5($key);
        $key_length=strlen($key);
        $string=$operation=='D'?base64_decode($string):substr(md5($string.$key),0,8).$string;
        $string_length=strlen($string);
        $rndkey=$box=array();
        $result='';
        for($i=0;$i<=255;$i++)
        {
            $rndkey[$i]=ord($key[$i%$key_length]);
            $box[$i]=$i;
        }
        for($j=$i=0;$i<256;$i++)
        {
            $j=($j+$box[$i]+$rndkey[$i])%256;
            $tmp=$box[$i];
            $box[$i]=$box[$j];
            $box[$j]=$tmp;
        }
        for($a=$j=$i=0;$i<$string_length;$i++)
        {
            $a=($a+1)%256;
            $j=($j+$box[$a])%256;
            $tmp=$box[$a];
            $box[$a]=$box[$j];
            $box[$j]=$tmp;
            $result.=chr(ord($string[$i])^($box[($box[$a]+$box[$j])%256]));
        }
        if($operation=='D')
        {
            if(substr($result,0,8)==substr(md5(substr($result,8).$key),0,8))
            {
                return substr($result,8);
            }
            else
            {
                return'';
            }
        }
        else
        {
            $rdate  = str_replace('=','',base64_encode($result));
            $rdate  = str_replace($src,$dist,$rdate);
            return $rdate;
        }
    }

 /**
 * “抽奖”函数
 *
 * @param integer $first    起始编号
 * @param integer $last     结束编号
 * @param integer $total    获奖人数
 *
 * @return string
 *
*/
function isWinner($first, $last, $total)
{
    $winner = array();
    for ($i=0;;$i++)
    {
        $number = mt_rand($first, $last);
        if (!in_array($number, $winner))
            $winner[] = $number;    // 如果数组中没有该数，将其加入到数组
        if (count($winner) == $total)   break;
    }
    return implode(' ', $winner);
}
// for test
// echo isWinner(1, 100, 30);
/**
 * [msginfo 消息提示,]
 * @param  [type] $msg       [STR, 字符型,提示信息]
 * @param  string $urlNumber [数字,-1为上一页,-2为上两页]
 * @return [type]            [description]
 */
function msginfo($msg,$urlNumber='-1'){
	echo "<script>alert('".$msg."');history.go(".$urlNumber.");</script>";
}

/**
 * [zeroCss 0和1的一个判断，1就显示为OK，或者对号，,]
 * @param  [type] $number       [STR, 字符型,提示信息]
 * @param  string $tyle [1，为对号和错号；2为OK和不OK]
 * @return [type]            [description]
 */
function zeroCss($number,$style="1"){
	if($number){
		if($style=="1"){
			echo "glyphicon glyphicon-ok-circle";
		}
		if($style=="2"){
			echo "glyphicon glyphicon-ok";
		}
	}else{
		if($style=="1"){
					echo "glyphicon glyphicon-remove-circle";
				}
		if($style=="2"){
			echo " glyphicon glyphicon-remove";
		}
	}
}
    /**
     * [returnMsg description]
     * @param  [type] $status [1.为成功，0为失败]
     * @param  [type] $style  [description]
     * @return [type]         [description]
     */
    function returnMsg($status,$style,$launage="zh"){
    	if($status){
    		 if($style=="add"){
    		 	if($launage=="zh"){
    		 		return $msg = "增加成功";
    		 	}elseif($launage=="en"){
    		 		return $msg = "sucess";
    		 	}
    		 	
    		 }

    	}else{
    		if($launage=="zh"){
    		 		return $msg = "增加失败";
    		 	}elseif($launage=="en"){
    		 		return $msg = "some error.pls check!";
    		 	}
    	}

    }